package com.gitee.wsl.compose.ui.richtext.edit.state

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.text.TextRange
import com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.type.startText


/**
 * The selection of the rich text.
 */
var RichTextState.selection
    get() = textFieldValue.selection
    set(value) {
        if (value.min >= 0 && value.max <= textFieldValue.text.length) {
            val newTextFieldValue = textFieldValue.copy(selection = value)
            updateTextFieldValue(newTextFieldValue)
        }
    }

fun RichTextState.isOnlySelectionChanged():Boolean{
    return tempTextFieldValue.text == textFieldValue.text &&
            tempTextFieldValue.selection != textFieldValue.selection
}

/**
 * Removes the selected text from the current text input.
 *
 * This method removes the text specified by the `selection` from the current text input.
 *
 * @see removeTextRange
 */
internal fun RichTextState.removeSelectedText() {
    removeTextRange(selection)
}

/**
 * Handles adding or removing the style in [toAddSpanStyle] and [toRemoveSpanStyle] from the selected text.
 */
internal fun RichTextState.applyRichSpanStyleToSelectedText() {
    applyRichSpanStyleToTextRange(selection)
}

/**
 * Replaces the currently selected text with the provided text.
 *
 * @param text The new text to be inserted
 */
fun RichTextState.replaceSelectedText(text: String) {
    removeSelectedText()
    addTextAfterSelection(text = text)
}

internal fun RichTextState.addTextAfterSelection(
    text: String
) {
    addText(
        text = text,
        index = selection.min
    )
}


/**
 * Adjusts the [selection] to the [pressPosition].
 * This is a workaround for the [TextField] that the [selection] is not always correct when you have multiple lines.
 *
 * @param pressPosition The press position.
 */
internal suspend fun RichTextState.adjustSelectionAndRegisterPressPosition(
    pressPosition: Offset,
) {
    adjustSelection(pressPosition)
    registerLastPressPosition(pressPosition)
}

/**
 * Adjusts the [selection] to the [pressPosition].
 * This is a workaround for the [TextField] that the [selection] is not always correct when you have multiple lines.
 *
 * @param pressPosition The press position.
 * @param newSelection The new selection.
 */
internal fun RichTextState.adjustSelection(
    pressPosition: Offset,
    newSelection: TextRange? = null,
) {
    val selection = newSelection ?: this.selection
    var pressX = pressPosition.x
    var pressY = pressPosition.y
    val textLayoutResult = this.textLayoutResult ?: return
    var index = 0
    for (i in 0 until textLayoutResult.lineCount) {
        index = i
        val start = textLayoutResult.getLineStart(i)
        val top = textLayoutResult.getLineTop(i)

        if (i == 0) {
            if (start > 0f) pressX += start
            if (top > 0f) pressY += top
        }

        if (i == 0 && top > pressY) break
        if (top > pressY) {
            index = i - 1
            break
        }
    }
    val selectedParagraph = richParagraphList.getOrNull(index) ?: return
    val nextParagraph = richParagraphList.getOrNull(index + 1)
    val nextParagraphStart =
        nextParagraph?.children?.firstOrNull()?.textRange?.min?.minus(nextParagraph.type.startText.length)
    if (
        selection.collapsed &&
        selection.min == nextParagraphStart
    )
        updateTextFieldValue(
            textFieldValue.copy(
                selection = TextRange(selection.min - 1, selection.min - 1)
            )
        )
    else if (
        selection.collapsed &&
        index == richParagraphList.lastIndex &&
        selectedParagraph.isEmpty() &&
        selection.min == selectedParagraph.getFirstNonEmptyChild()?.textRange?.min?.minus(1)
    )
        updateTextFieldValue(
            textFieldValue.copy(
                selection = TextRange(selection.min + 1, selection.min + 1)
            )
        )
    else if (newSelection != null)
        updateTextFieldValue(
            textFieldValue.copy(
                selection = newSelection
            )
        )
}